package com.szakul.pdf.model;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
import org.pdfclown.documents.Page;
import org.pdfclown.documents.contents.ITextString;
import org.pdfclown.documents.contents.TextChar;
import org.pdfclown.files.File;

import org.pdfclown.tools.TextExtractor;
import org.pdfclown.util.math.Interval;
import org.pdfclown.util.math.geom.Quad;


public class TextHighlighter {

	private static final Logger LOGGER = Logger.getLogger(TextHighlighter.class);
	
	private String fileName;

	private File file;

	private BufferedImage highlightPage = null;

	public TextHighlighter(String fileName) {

		this.fileName = fileName;
	}

	public List<Integer> getMatchPages(final String textRegEx) {

		final Map <Integer, Integer> resultMap = new HashMap<Integer, Integer>();

		try {
			file = new File(fileName);
		} catch (Exception e) {
			throw new RuntimeException(fileName + " file access error.", e);
		}

		Pattern pattern = Pattern.compile(textRegEx, Pattern.CASE_INSENSITIVE);

		// 2. Iterating through the document pages...
		TextExtractor textExtractor = new TextExtractor(true, true);

		for (final Page page : file.getDocument().getPages()) {

			// 2.1. Extract the page text!
			Map<Rectangle2D, List<ITextString>> textStrings = textExtractor
					.extract(page);

			// 2.2. Find the text pattern matches!
			final Matcher matcher = pattern.matcher(TextExtractor
					.toString(textStrings));

			// 2.3. Highlight the text pattern matches!
			textExtractor.filter(textStrings,
					new TextExtractor.IIntervalFilter() {
						public boolean hasNext() {
							return matcher.find();
						}

						public Interval<Integer> next() {
							return new Interval<Integer>(matcher.start(),
									matcher.end());
						}

						public void process(Interval<Integer> interval,
								ITextString match) {

							LOGGER.debug("Match page "
									+ (page.getIndex() + 1));
							
							int pageIndex = page.getIndex();
							Integer page = Integer.valueOf((pageIndex + 1));
							resultMap.put(page, page);


						}

						public void remove() {
							throw new UnsupportedOperationException();
						}
					});

		}
		return new ArrayList<Integer>(resultMap.keySet());

	}

	private List<Quad> getQuads(int pageNumber, String text) {

		final List<Quad> highlightQuads = new ArrayList<Quad>();

		try {
			file = new File(fileName);
		} catch (Exception e) {
			throw new RuntimeException(fileName + " file access error.", e);
		}

		Pattern pattern = Pattern.compile(text, Pattern.CASE_INSENSITIVE);

		// 2. Iterating through the document pages...
		TextExtractor textExtractor = new TextExtractor(true, true);

		final Page page = file.getDocument().getPages().get(pageNumber - 1);

		// 2.1. Extract the page text!
		Map<Rectangle2D, List<ITextString>> textStrings = textExtractor
				.extract(page);

		// 2.2. Find the text pattern matches!
		final Matcher matcher = pattern.matcher(TextExtractor
				.toString(textStrings));

		// 2.3. Highlight the text pattern matches!
		textExtractor.filter(textStrings, new TextExtractor.IIntervalFilter() {
			public boolean hasNext() {
				return matcher.find();
			}

			public Interval<Integer> next() {
				return new Interval<Integer>(matcher.start(), matcher.end());
			}

			public void process(Interval<Integer> interval, ITextString match) {

				/*
				 * NOTE: A text pattern match may be split across multiple
				 * contiguous lines, so we have to define a distinct highlight
				 * box for each text chunk.
				 */
				Rectangle2D textBox = null;

				for (TextChar textChar : match.getTextChars()) {

					Rectangle2D textCharBox = textChar.getBox();
					if (textBox == null) {
						textBox = (Rectangle2D) textCharBox.clone();
					} else {

						if (textCharBox.getY() > textBox.getMaxY()) {
							highlightQuads.add(Quad.get(textBox));
							textBox = (Rectangle2D) textCharBox.clone();
						} else {
							textBox.add(textCharBox);
						}
					}
				}

				highlightQuads.add(Quad.get(textBox));

			}

			public void remove() {
				throw new UnsupportedOperationException();
			}
		});
		return highlightQuads;
	}

	public BufferedImage highlightPage(final BufferedImage image,
			int pageNumber, String text) {

		highlightPage = null;

		final Color transparent = new Color(255, 0, 0, 64);

		List<Quad> highlightQuads = getQuads(pageNumber, text);
		
		LOGGER.debug(" highlightPage size: " + highlightQuads.size());
		final Graphics g2d = image.getGraphics();
		g2d.setColor(transparent);

		for (Quad q : highlightQuads) {

			Rectangle2D rec = q.getBounds2D();

			int x = (int) rec.getX();
			int y = (int) (image.getHeight() / 2 - rec.getY() - rec.getHeight());
			int w = (int) rec.getWidth();
			int h = (int) rec.getHeight();
			LOGGER.debug("x: " + x + " y: " + y);
			g2d.fillRect(x, y, w, h);
			

		}
		
		g2d.dispose();

		try {
			ImageIO.write(image, "png", new java.io.File("test.png"));
		} catch (IOException e) {
			LOGGER.error("Image IO write", e);
			
		}
		highlightPage = com.szakul.pdf.utl.Utilities.toBufferedImage(image);

		return highlightPage;
	}

}
